package com.byd.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import com.byd.model.Path;

public final class Lg extends BroadcastReceiver {
	private static final String TAG = "SystemUpdate";
	public static final String BASE_TAG = TAG + ".";
	private static final String ACTION = "byd.action.log";
	private static final String EXTRA_PACKAGE = "package";
	private static final String EXTRA_LOG_FLAG = "flag";
	private static String sPackageName;
	private static final int FLAG_V = 0x01;
	private static final int FLAG_D = 0x02;
	private static final int FLAG_I = 0x04;
	private static final int FLAG_W = 0x08;
	private static final int FLAG_E = 0x10;
	private static final int FLAG_WTF = 0x20;
	private static final int FLAG_SAVE_EXCEPTION = 0x40;
	private static int DEBUG = FLAG_V | FLAG_D | FLAG_I | FLAG_W | FLAG_E | FLAG_WTF | FLAG_SAVE_EXCEPTION;
	private static Lg sLg;
	private Context mContext;

	public static void init(Context context) {
		if(sLg == null) {
			sLg = new Lg(context);
		}
	}

	public static void release() {
		if(sLg != null) {
			sLg.releaseInner();
		}
		sLg = null;
	}

	private Lg(Context context) {
		mContext = context.getApplicationContext();
		sPackageName = context.getPackageName();
		final IntentFilter filter = new IntentFilter(ACTION);
		mContext.registerReceiver(this, filter);
	}

	@Override
	public void onReceive(Context context, Intent intent) {
		if(intent != null && ACTION.equals(intent.getAction())) {
			final String packageName = intent.getStringExtra(EXTRA_PACKAGE);
			if(context.getPackageName().equals(packageName)) {
				final int flag = intent.getIntExtra(EXTRA_LOG_FLAG, 0);
				debugEnable(flag);
			}
		}
	}

	private void releaseInner() {
		mContext.unregisterReceiver(this);
		mContext = null;
	}

	public static void debugEnable(int level) {
		if(DEBUG != level) {
			DEBUG = level;
			final StringBuilder builder = new StringBuilder("open debug mode: [");
			boolean enabled = false;
			if((DEBUG & FLAG_V) == FLAG_V) {
				builder.append("V");
				enabled = true;
			}
			if((DEBUG & FLAG_D) == FLAG_D) {
				if(enabled) {
					builder.append(", ");
				}
				builder.append("D");
				enabled = true;
			}
			if((DEBUG & FLAG_I) == FLAG_I) {
				if(enabled) {
					builder.append(", ");
				}
				builder.append("I");
				enabled = true;
			}
			if((DEBUG & FLAG_W) == FLAG_W) {
				if(enabled) {
					builder.append(", ");
				}
				builder.append("W");
				enabled = true;
			}
			if((DEBUG & FLAG_E) == FLAG_E) {
				if(enabled) {
					builder.append(", ");
				}
				builder.append("E");
				enabled = true;
			}
			if((DEBUG & FLAG_WTF) == FLAG_WTF) {
				if(enabled) {
					builder.append(", ");
				}
				builder.append("WTF");
				enabled = true;
			}
			builder.append("]");
			if(enabled) {
				Log.d(TAG, builder.toString());
			}
			else {
				Log.d(TAG, "close debug mode!");
			}
		}
	}

	public static void v(String tag, Object msg) {
		if((DEBUG & FLAG_V) == FLAG_V) {
			Log.v(tag, String.valueOf(msg));
		}
	}

	public static void d(String tag, Object msg) {
		if((DEBUG & FLAG_D) == FLAG_D) {
			Log.d(tag, String.valueOf(msg));
		}
	}

	public static void i(String tag, Object msg) {
		if((DEBUG & FLAG_I) == FLAG_I) {
			Log.i(tag, String.valueOf(msg));
		}
	}

	public static void w(String tag, Object msg) {
		if((DEBUG & FLAG_W) == FLAG_W) {
			Log.w(tag, String.valueOf(msg));
		}
	}

	public static void e(String tag, Object msg) {
		if((DEBUG & FLAG_E) == FLAG_E) {
			Log.e(tag, String.valueOf(msg));
		}
	}

	public static void wtf(String tag, Object msg) {
		if((DEBUG & FLAG_WTF) == FLAG_WTF) {
			Log.wtf(tag, String.valueOf(msg));
		}
	}

	public static void printStackTrace(Throwable e) {
		if((DEBUG & FLAG_W) == FLAG_W) {
			if(e != null) {
				e.printStackTrace();
			}
			else {
				final Thread thread = Thread.currentThread();
				final StackTraceElement[] traceElements = thread.getStackTrace();
				final StackTraceElement element = traceElements[3];
				String tag = BASE_TAG;
				tag += element.getClassName().substring(element.getClassName().lastIndexOf(".") + 1);
				final String msg = element.getMethodName() + "(line: " + element.getLineNumber() + ")";
				e(tag, "printStackTrace: Throwable = null, at: " + msg);
			}
		}
		saveStackTrace(e);
	}

	public static void v(Object msg) {
		final String tag = BASE_TAG + getClassName();
		v(tag, msg);
	}

	public static void d(Object msg) {
		final String tag = BASE_TAG + getClassName();
		d(tag, msg);
	}

	public static void i(Object msg) {
		final String tag = BASE_TAG + getClassName();
		i(tag, msg);
	}

	public static void w(Object msg) {
		final String tag = BASE_TAG + getClassName();
		w(tag, msg);
	}

	public static void e(Object msg) {
		final String tag = BASE_TAG + getClassName();
		e(tag, msg);
	}

	public static void wtf(Object msg) {
		final String tag = BASE_TAG + getClassName();
		wtf(tag, msg);
	}

	public static void mark() {
		final Thread thread = Thread.currentThread();
		final StackTraceElement[] traceElements = thread.getStackTrace();
		final StackTraceElement element = traceElements[3];
		String tag = BASE_TAG;
		tag += element.getClassName().substring(element.getClassName().lastIndexOf(".") + 1);
		final String msg = element.getMethodName() + "(line: " + element.getLineNumber() + ", time: "
				+ System.currentTimeMillis() + ")";
		i(tag, msg);
	}

	private static String getClassName() {
		final Thread thread = Thread.currentThread();
		final StackTraceElement[] traceElements = thread.getStackTrace();
		final StackTraceElement element = traceElements[4];
		return element.getClassName().substring(element.getClassName().lastIndexOf(".") + 1);
	}

	public static void saveStackTrace(Throwable ex) {
		if((DEBUG & FLAG_SAVE_EXCEPTION) == FLAG_SAVE_EXCEPTION && ex != null) {
			Writer writer = null;
			PrintWriter printWriter = null;
			FileOutputStream stream = null;
			try {
				writer = new StringWriter();
				printWriter = new PrintWriter(writer);
				ex.printStackTrace(printWriter);
				final File file = new File(Path.LOG, "AppExc.log");
				stream = new FileOutputStream(file, true);
				stream.write((getHeadInfo() + writer.toString() + "\r\n\r\n").getBytes());
			}
			catch (final Exception e) {
				Lg.w("saveStackTrace failed: " + e.getMessage());
			}
			finally {
				try {
					if(printWriter != null) {
						printWriter.close();
					}
				}
				catch (final Exception e) {
					Lg.w("print writer close failed: " + e.getMessage());
				}
				try {
					if(writer != null) {
						writer.close();
					}
				}
				catch (final Exception e) {
					Lg.w("writer close failed: " + e.getMessage());
				}
				try {
					if(stream != null) {
						stream.close();
					}
				}
				catch (final Exception e) {
					Lg.w("stream close failed: " + e.getMessage());
				}
			}
		}
	}

	private static String getHeadInfo() {
		return "\r\n\r\n" + "[" + sPackageName + ": " + CommonUtils.getDayTime(System.currentTimeMillis()) + "]\r\n";
	}
}
